package zemberek3.crosscheck;

import com.google.common.base.Charsets;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.google.common.io.Resources;
import org.jcaki.SimpleTextWriter;
import zemberek3.ambiguity.AbstractDisambiguator;
import zemberek3.apps.TurkishMorphParser;
import zemberek3.apps.UnidentifiedTokenParser;
import zemberek3.parser.morphology.MorphParse;
import zemberek3.shared.lexicon.SecondaryPos;
import zemberek3.structure.Turkish;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

public class ConvertDisambiguationData {

    TurkishMorphParser parser;
    UnidentifiedTokenParser unidentifiedTokenParser;

    public ConvertDisambiguationData(TurkishMorphParser parser) {
        this.parser = parser;
        unidentifiedTokenParser = new UnidentifiedTokenParser(parser);
    }

    public void convert(File in, File out) throws IOException {
        AbstractDisambiguator.DataSet set = Files.readLines(in, Charsets.UTF_8, new AbstractDisambiguator.DataSetLoader());
        SimpleTextWriter stw = SimpleTextWriter.keepOpenUTF8Writer(out);
        stw.writeLine("<DOC>");
        for (AbstractDisambiguator.SentenceData sentenceData : set) {

            List<MorphParse> results;
            boolean skipSentence = false;
            List<String> lines = Lists.newArrayList();
            for (AbstractDisambiguator.WordData word : sentenceData.words) {
                String normalized = parser.normalize(word.word);
                normalized = normalized.replaceAll("'", "");
                if (normalized.length() == 0)
                    continue;
                results = parser.parse(normalized);
                if (results.size() == 0 || (Character.isUpperCase(word.word.charAt(0)) && !hasProperParse(results)))
                    results.addAll(unidentifiedTokenParser.parse(word.word));
                if (results.size() == 0) {
                    System.out.println("No parse for:" + word.word);
                    skipSentence = true;
                    continue;
                }
                int correctIndex = findCorrectParse(word.correctParse, results);
                if (correctIndex == -1) {
                    dumpParses(word, results);
                    correctIndex = findLongestRootIndex(results);
                }
                switchBest(results, correctIndex);
                StringBuilder sb = new StringBuilder();
                int j = 0;
                for (MorphParse result : results) {
                    sb.append(result.formatNoSurface());
                    if (j < results.size() - 1)
                        sb.append("|");
                    j++;
                }
                lines.add(word.word + "=" + sb.toString());
            }

            if (!skipSentence) {
                stw.writeLine("<S>");
                stw.writeLines(lines);
                stw.writeLine();
                stw.writeLine("</S>");
            }

        }
        stw.writeLine("</DOC>");
        stw.close();
    }

    private void switchBest(List<MorphParse> results, int index) {
        MorphParse tmp = results.get(0);
        results.set(0, results.get(index));
        results.set(index, tmp);
    }

    static Map<String, String> oflazerCleanerTable = Maps.newHashMap();

    static {
        oflazerCleanerTable.put("Zero", "");
        oflazerCleanerTable.put("PCNom", "");
        oflazerCleanerTable.put("PCDat", "");
        oflazerCleanerTable.put("PCLoc", "");
        oflazerCleanerTable.put("PCAbl", "");
        oflazerCleanerTable.put("PCIns", "");
        oflazerCleanerTable.put("Verb^DB+Verb", "Verb");
    }

    static Map<String, String> z3CleanerTable = Maps.newHashMap();

    static {
        z3CleanerTable.put("Time", "");
        z3CleanerTable.put("Verb^DB+Verb", "Verb");
    }

    private void dumpParses(AbstractDisambiguator.WordData word, List<MorphParse> results) {
        System.out.println("------PROBLEM-------");
        for (MorphParse re : results) {
            System.out.println(re.formatOflazer());
        }
        System.out.println("---");
        for (String str : word.allParses) {
            System.out.println(str);
        }
        System.out.println("-------------------");
    }

    private boolean hasProperParse(List<MorphParse> results) {
        for (MorphParse res : results) {
            if (res.dictionaryItem.secondaryPos == SecondaryPos.ProperNoun)
                return true;
        }
        return false;
    }

    public int findCorrectParse(String oflazerCorrectParse, List<MorphParse> parses) {
        if (parses.size() == 1)
            return 0;
        oflazerCorrectParse = cleanOflazer(oflazerCorrectParse);
        oflazerCorrectParse = oflazerCorrectParse.toLowerCase(Turkish.LOCALE);
        if (oflazerCorrectParse.endsWith("+"))
            oflazerCorrectParse = oflazerCorrectParse.substring(0, oflazerCorrectParse.length() - 1);
        List<String> formatted = Lists.newArrayList();

        for (MorphParse parse : parses) {
            String s = cleanZ3(parse.formatOflazer());
            formatted.add(s.toLowerCase(Turkish.LOCALE));
        }

        for (int i = 0; i < formatted.size(); i++) {
            if (formatted.get(i).equals(oflazerCorrectParse))
                return i;
        }
        return findMostSimilarIndex(formatted, oflazerCorrectParse);
    }

    private String cleanOflazer(String inp) {
        for (String s : oflazerCleanerTable.keySet()) {
            inp = inp.replaceAll(s, oflazerCleanerTable.get(s));
        }
        return inp.replaceAll("[+]+", "+");
    }

    private String cleanZ3(String inp) {
        for (String s : z3CleanerTable.keySet()) {
            inp = inp.replaceAll(s, z3CleanerTable.get(s));
        }
        return inp.replaceAll("[+]+", "+");

    }

    LevenshteinCharDistance disCalc = new LevenshteinCharDistance();


    public int findMostSimilarIndex(List<String> parses, String correctParse) {
        int i = 0, j = -1;
        double closest = 1000d;
        for (String parse : parses) {
            double distance = disCalc.distance(parse, correctParse);
            if (distance < closest) {
                closest = distance;
                j = i;
            }
            i++;
        }
        return j;
    }

    public int findLongestRootIndex(List<MorphParse> parses) {
        int i = 0, j = -1;
        int longest = -1;
        for (MorphParse parse : parses) {
            if (parse.stem.length() > longest) {
                longest = parse.stem.length();
                j = i;
            }
            i++;
        }
        return j;
    }


    public static void main(String[] args) throws IOException {
        TurkishMorphParser morphParser = TurkishMorphParser.newBuilder()
                .addTextDictFiles(
                        new File(Resources.getResource("tr/master-dictionary.dict").getFile()),
                        new File(Resources.getResource("tr/secondary-dictionary.dict").getFile()),
                        new File(Resources.getResource("tr/proper.dict").getFile()),
                        new File(Resources.getResource("tr/non-tdk.dict").getFile()))
                .build();
        File workDir = new File("/home/afsina/apps/nlp/sak");
        new ConvertDisambiguationData(morphParser).convert(
                new File(workDir, "test.merge"),
                new File(workDir, "test.z3.merge")
        );

    }
}
